import base64
import json
import pickle

from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection

from goods.models import SKU


class CartsView(View):
    def get(self, request):

        cart_skus = []

        user = request.user
        if user.is_authenticated:
            redis_client = get_redis_connection('carts')

            sku_ids = redis_client.hkeys('cart_%s' % user.id)
            sku_selected = redis_client.smembers('selected_%s' % user.id)

            for sku_id in sku_ids:
                sku = SKU.objects.get(id=sku_id)
                count = redis_client.hget('cart_%s' % user.id, sku_id)
                sku_data = {
                    "id": sku.id,
                    "selected": str(sku_id in sku_selected),
                    "count": int(count),
                    "price": float(sku.price),
                    "default_image_url": sku.default_image_url.url,
                    "name": sku.name,
                    'amount': float(sku.price * int(count)),
                }
                cart_skus.append(sku_data)
            context = {
                "cart_skus": cart_skus
            }
            return render(request, 'cart.html', context=context)

        else:
            carts = request.COOKIES.get('carts')
            if carts:
                cart_dict = pickle.loads(base64.b64decode(carts))

                for sku_id in cart_dict:
                    count = cart_dict[sku_id]['count']
                    selected = cart_dict[sku_id]['selected']
                    sku = SKU.objects.get(id=sku_id)
                    sku_data = {
                        "id": sku.id,
                        "selected": str(selected),
                        "count": int(count),
                        "price": float(sku.price),
                        "default_image_url": sku.default_image_url.url,
                        "name": sku.name,
                        'amount': float(sku.price * int(count)),
                    }
                    cart_skus.append(sku_data)
            else:
                cart_skus = []

            context = {
                "cart_skus": cart_skus
            }
            return render(request, 'cart.html', context=context)

    def post(self, request):

        recv_data = json.loads(request.body.decode())

        sku_id = recv_data.get('sku_id')
        count = recv_data.get('count')

        if not all([sku_id, count]):
            return JsonResponse({'code': 9999, 'errmsg': 'arguments lost'})

        try:
            sku = SKU.objects.get(id=sku_id)
        except:
            return JsonResponse({'code': 9999, 'errmsg': 'wrong SKU ID'})

        try:
            count = int(count)
            if count < 1:
                return JsonResponse({'code': 9999, 'errmsg': 'count is too small'})
        except:
            return JsonResponse({'code': 9999, 'errmsg': 'count is not an integer'})

        user = request.user
        if user.is_authenticated:

            redis_client = get_redis_connection('carts')
            user_cart = 'cart_%s' % user.id
            user_selected = 'selected_%s' % user.id

            redis_client.sadd(user_selected, sku_id)
            old_count = redis_client.hget(user_cart, sku_id)
            try:
                old_count = int(old_count)
                if old_count >= 1:
                    redis_client.hset(user_cart, sku_id, old_count + count)
            except:
                redis_client.hset(user_cart, sku_id, count)

            res = {
                'code': 0,
                'errmsg': 'OK',
                'sku_count': count
            }
            response = JsonResponse(res)
            response.delete_cookie('carts')
            return response

        else:

            old_carts = request.COOKIES.get('carts')

            if old_carts:
                cart_dict = pickle.loads(base64.b64decode(old_carts))

                if sku_id in cart_dict:
                    cart_dict[sku_id]['count'] += count

                else:
                    cart_dict[sku_id] = {
                        'count': count,
                        'selected': True
                    }

            else:

                cart_dict = {
                    sku_id: {
                        'count': count,
                        'selected': True
                    }
                }

            byte8_cart = pickle.dumps(cart_dict)
            base64_cart = base64.b64encode(byte8_cart)

            res = {
                'code': 0,
                'errmsg': 'OK',
                'sku_count': count
            }

            response = JsonResponse(res)
            response.set_cookie('carts', base64_cart, expires=3600 * 24 * 14)

            return response

    def put(self, request):

        recv_data = json.loads(request.body.decode())
        sku_id = recv_data.get('sku_id')
        count = recv_data.get('count')
        selected = recv_data.get('selected')

        try:
            sku = SKU.objects.get(id=sku_id)
        except:
            return JsonResponse({'code': 9999, 'errmsg': 'wrong SKU ID'})

        try:
            count = int(count)
        except:
            return JsonResponse({'code': 9999, 'errmsg': 'not a number'})

        if count < 1:
            return JsonResponse({'code': 9999, 'errmsg': 'count is too small'})

        user = request.user

        if user.is_authenticated:
            redis_client = get_redis_connection('carts')

            redis_client.hset('cart_%s' % user.id, sku_id, count)

            if selected:
                redis_client.sadd('selected_%s' % user.id, sku_id)
            else:
                redis_client.srem('selected_%s' % user.id, sku_id)

            res = {
                'code': '0',
                'errmsg': 'OK',
                'cart_sku': {
                    'id': sku.id,
                    'name': sku.name,
                    'price': float(sku.price),
                    'count': int(count),
                    'default_image_url': sku.default_image_url.url,
                    'amount': float(sku.price * int(count)),
                    'selected': selected
                }
            }
            return JsonResponse(res)

        else:
            carts_data = request.COOKIES.get('carts')

            try:
                cart_dict = pickle.loads(base64.b64decode(carts_data))
            except:
                return JsonResponse({'code': 9999, 'errmsg': 'carts is empty'})

            cart_dict[sku_id] = {'count': count, 'selected': selected}

            res = {
                'code': 0,
                'errmsg': 'OK',
                'cart_sku': {
                    'id': sku.id,
                    'name': sku.name,
                    'price': float(sku.price),
                    'count': int(count),
                    'default_image_url': sku.default_image_url.url,
                    'amount': float(sku.price * int(count)),
                    'selected': selected
                }
            }

            response = JsonResponse(res)

            carts = base64.b64encode(pickle.dumps(cart_dict))
            response.set_cookie('carts', carts, expires=3600 * 24 * 14)
            return response

    def delete(self, request):

        recv_data = json.loads(request.body.decode())
        sku_id = recv_data.get('sku_id')

        if not sku_id:
            return JsonResponse({'code': 9999, 'errmsg': 'missing SKU ID'})

        try:
            sku = SKU.objects.get(id=sku_id)
        except:
            return JsonResponse({'code': 9999, 'errmsg': 'wrong SKU ID'})

        user = request.user

        if user.is_authenticated:
            redis_client = get_redis_connection('carts')
            if redis_client.hget('cart_%s' % user.id, sku_id):
                redis_client.hdel('cart_%s' % user.id, sku_id)
            else:
                return JsonResponse({'code': 9999, 'errmsg': 'SKU is not existed'})

            redis_client.srem('selected_%s' % user.id, sku_id)

            res = {
                'code': 0,
                'errmsg': 'OK'
            }
            return JsonResponse(res)
        else:
            cart_data = request.COOKIES.get('carts')
            cart_dict = pickle.loads(base64.b64decode(cart_data))

            if sku_id in cart_dict:
                del cart_dict[sku_id]
                response = JsonResponse({'code': 0, 'errmsg': 'OK'})
                cart_data = base64.b64encode(pickle.dumps(cart_dict))
                response.set_cookie('carts', cart_data, expires=3600 * 24 * 14)
                return response

            else:
                return JsonResponse({'code': 9999, 'errmsg': 'SKU is not existed'})


class CartsSelectionView(View):
    def put(self, request):

        recv_data = json.loads(request.body.decode())
        selected = recv_data.get('selected')

        user = request.user

        if user.is_authenticated:
            redis_client = get_redis_connection('carts')
            sku_ids = redis_client.hkeys('cart_%s' % user.id)

            if selected:
                redis_client.sadd('selected_%s' % user.id, *sku_ids)
            else:
                redis_client.srem('selected_%s' % user.id, *sku_ids)

            res = {
                'code': 0,
                'errmsg': 'OK'
            }
            return JsonResponse(res)

        else:
            carts = request.COOKIES.get('carts')

            if not carts:
                return JsonResponse({'code': 9999, 'errmsg': 'cart is empty'})

            cart_dict = pickle.loads(base64.b64decode(carts))

            for sku_id in cart_dict:
                cart_dict[sku_id]['selected'] = selected

            res = {
                'code': 0,
                'errmsg': 'OK'
            }
            response = JsonResponse(res)

            carts = base64.b64encode(pickle.dumps(cart_dict))
            response.set_cookie('carts', carts, expires=3600 * 24 * 14)
            return response


class CartsSimpleView(View):
    def get(self, request):

        cart_skus = []

        user = request.user

        if user.is_authenticated:

            redis_client = get_redis_connection('carts')
            sku_ids = redis_client.hkeys('cart_%s' % user.id)

            for sku_id in sku_ids:
                sku = SKU.objects.get(id=sku_id)
                sku_data = {
                    'name': sku.name,
                    'default_image_url': sku.default_image_url.url,
                    'count': int(redis_client.hget('cart_%s' % user.id, sku_id))
                }
                cart_skus.append(sku_data)

            res = {
                'code': 0,
                'errmsg': 'OK',
                'cart_skus': cart_skus
            }

            return JsonResponse(res)

        else:

            carts = request.COOKIES.get('carts')

            try:
                cart_dict = pickle.loads(base64.b64decode(carts))
            except:
                cart_dict = []

            for sku_id in cart_dict:
                sku = SKU.objects.get(id=sku_id)
                sku_data = {
                    'name': sku.name,
                    'default_image_url': sku.default_image_url.url,
                    'count': int(cart_dict[sku_id]['count'])
                }

                cart_skus.append(sku_data)

            res = {
                'code': 0,
                'errmsg': 'OK',
                'cart_skus': cart_skus
            }
            return JsonResponse(res)
